import socket
import urllib.parse
import threading

from routes.routes_static import route_static
from routes.routes_user import route_dict as user_routes
from routes.routes_weibo import route_dict as weibo_routes
from routes.todo import route_dict as todo_routes
from routes.api_todo import route_dict as api_todo
from utils import (
    log,
    error,
)


class Request(object):
    def __init__(self, request):
        '''
        解析请求
        '''
        log(request)
        self.request = request
        self.method = request.split()[0]
        self.path = request.split()[1].split('?')[0]
        self.query = self.get_query()
        self.headers = self.get_headers()
        self.cookies = self.get_cookies()
        self.body = request.split('\r\n\r\n')[1]

    def __repr__(self):
        '''
        格式化打印请求
        '''
        log('Method', self.method)
        log('Path', self.path)
        log('Query', self.query)
        log('Cookies', self.cookies)
        log('Headers', self.headers)
        log('Body', self.body)
        return self.request

    def get_query(self):
        '''
        从request中解析出query字典
        '''
        path_query = self.request.split()[1]
        if '?' not in path_query:
            return None
        query = {}
        query_list = path_query.split('?')[1].split('&')
        for arg in query_list:
            k, v = arg.split('=')
            query[k] = v
        return query

    def get_headers(self):
        '''
        得到响应头
        '''
        header = self.request.split('\r\n\r\n')[0].split('\r\n')[1:]
        headers = {}
        for arg in header:
            k, v = arg.split(': ', 1)
            headers[k] = v
        return headers

    def get_cookies(self):
        '''
        解析出cookie，以一个字典形式返回
        :return:
        '''
        cookies = {}
        cookie = self.headers.get('Cookie', '')
        if cookie is '':
            return {}
        args = cookie.split(':')
        for arg in args:
            k, v = arg.split('=')
            cookies[k] = v
        return cookies

    def form(self):
        '''
        解析出post请求的表单数据
        :return:
        '''
        #使用urllib库可以解析body中的特殊字符
        body = urllib.parse.unquote(self.body)
        # body = self.body
        args = body.split('&')
        f = {}
        for arg in args:
            k, v = arg.split('=')
            f[k] = v
        return f

    def json(self):
        """
        解析body中的json数据
        """
        import json
        return json.loads(self.body)


def parsed_path(path):
    """
    message=hello&author=gua
    {
        'message': 'hello',
        'author': 'gua',
    }
    """
    index = path.find('?')
    if index == -1:
        return path, {}
    else:
        path, query_string = path.split('?', 1)
        args = query_string.split('&')
        query = {}
        for arg in args:
            k, v = arg.split('=')
            query[k] = v
        return path, query


def response_for_path(request):
    path, query = request.path, request.query
    log('path and query', path, query)
    """
    根据 path 调用相应的处理函数
    没有处理的 path 会返回 404
    """
    r = {
        '/static': route_static,
    }
    # 注册外部的路由
    r.update(api_todo)
    r.update(user_routes)
    r.update(todo_routes)
    r.update(weibo_routes)
    response = r.get(path, error)
    return response(request)


def process_request(connection):
    buffer_size = 2048
    request_str = b''
    #接受全部数据
    while True:
        r = connection.recv(buffer_size)
        if len(r) < buffer_size:
            request_str += r
            break
        request_str += r
    request_str = request_str.decode('utf-8')
    if len(request_str.split()) < 2:
        connection.close()
    request = Request(request_str)          #根据请求的数据生成request对象
    response = response_for_path(request)   #根据request对象生成相应
    connection.sendall(response)            #返回响应
    connection.close()
    print('一个连接结束')


def main(host='', port=3000):
    """
    启动服务器
    """
    print('start at', '{}:{}'.format(host, port))
    with socket.socket() as s:
        s.bind((host, port))
        s.listen(4)
        while True:
            connection, address = s.accept()
            print('连接成功', address)
            #开启多线程来处理请求
            threading._start_new_thread(process_request, (connection,))


if __name__ == '__main__':
    main(host='', port=3000,)
